using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using NUnit.Framework;
using Com.ContentRendering.Api.ParserEngine;
using Com.ContentRendering.Api.ParserEngine.Exceptions;
using Com.ContentRendering.Api.ParserEngineComponentTest.Helper;

namespace Com.ContentRendering.Api.ParserEngineComponentTest
{
    [TestFixture]
    public class ComponentTest
    {
        /// <summary/>
        private class SpecialCharactersContext : SpecialCharactersInterface
        {
            /// <summary/>
            public char Substitution
            {
                get { return ':'; }
            }

            /// <summary/>
            public char Escape
            {
                get { return '$'; }
            }

            /// <summary/>
            public char If
            {
                get { return '?'; }
            }

            /// <summary/>
            public char IfNot
            {
                get { return '!'; }
            }

            /// <summary/>
            public char Start
            {
                get { return '['; }
            }

            /// <summary/>
            public char Child
            {
                get { return '.'; }
            }

            /// <summary/>
            public char End
            {
                get { return ']'; }
            }

            /// <summary/>
            public char Transparent
            {
                get { return '~'; }
            }

            /// <summary/>
            public char Parent
            {
                get { return '*'; }
            }
        }

        private Dictionary<string, string> _resources;

        [TestFixtureSetUp]
        public void SetUpFixture()
        {
            this._resources = new Dictionary<string, string>();

            Assembly assembly = Assembly.GetExecutingAssembly();

            foreach (string typeFullName in assembly.GetManifestResourceNames())
            {
                using (Stream stream = assembly.GetManifestResourceStream(typeFullName))
                {
                    using (TextReader textReader = new StreamReader(stream))
                    {
                        this._resources.Add(typeFullName, textReader.ReadToEnd());
                    }
                }
            }
        }

        private DocumentParser _documentParser;
        private OutputNodeInterface _outputNodeHelper;

        [SetUp]
        public void SetUp()
        {
            this._documentParser = new DocumentParser(new SpecialCharactersContext());
            this._outputNodeHelper = new OutputNodeHelper();
        }

        [Test]
        public void ContentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.Content.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.Content.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void EscapeTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.Escape.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.Escape.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.Tag.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.Tag.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagNestedTagChildTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNestedTagChild.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagNestedTagChild.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagNestedTagParentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNestedTagParent.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagNestedTagParent.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagTransparentNestedContentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagTransparentNestedContent.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagTransparentNestedContent.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagIfNotNestedContentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagIfNotNestedContent.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagIfNotNestedContent.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagNestedContentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNestedContent.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagNestedContent.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagTwiceParentTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagTwiceParent.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.TagTwiceParent.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void ComplexOneTest()
        {
            this._documentParser.Parse(
                this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.ComplexOne.tem"],
                this._outputNodeHelper);

            XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Output.ComplexOne.xml"]);

            Assert.AreEqual(
                xmlDocument.OuterXml,
                this._outputNodeHelper.ToString());
        }

        [Test]
        public void TagNameEmptyTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNameEmpty.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 01);
                Assert.AreEqual(exception.Column, 3);
                Assert.AreEqual(exception.Value, ']');
                Assert.AreEqual(exception.DebugBuffer, "[.");
                Assert.IsInstanceOf(typeof(TagNameEmptyException), exception.InnerException);
                                
                return;
            }

            Assert.Fail();
        }

        [Test]
        public void TagNameInvalidOneTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNameInvalidOne.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 6);
                Assert.AreEqual(exception.Value, '1');
                Assert.AreEqual(exception.DebugBuffer, "[test");
                Assert.IsInstanceOf(typeof(TagNameInvalidException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }

        [Test]
        public void TagNameInvalidTwoTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagNameInvalidTwo.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 6);
                Assert.AreEqual(exception.Value, '.');
                Assert.AreEqual(exception.DebugBuffer, "[test");
                Assert.IsInstanceOf(typeof(TagNameInvalidException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }

        [Test]
        public void MissingStartTagTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.MissingStartTag.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 5);
                Assert.AreEqual(exception.Value, ']');
                Assert.AreEqual(exception.DebugBuffer, "test");
                Assert.IsInstanceOf(typeof(MissingStartCharacterException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }

        [Test]
        public void MissingEndTagTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.MissingEndTag.tem"],
                    this._outputNodeHelper);
            }
            catch (MissingEndCharacterException)
            {
                return;
            }

            Assert.Fail();
        }

        [Test]
        public void MissingEscapeTagTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.MissingEscapeTag.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 6);
                Assert.AreEqual(exception.Value, 't');
                Assert.AreEqual(exception.DebugBuffer, "test$");
                Assert.IsInstanceOf(typeof(MissingEscapeCharacterException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }

        [Test]
        public void TagChildTagTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagChildTag.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 9);
                Assert.AreEqual(exception.Value, '.');
                Assert.AreEqual(exception.DebugBuffer, "[testOne");
                Assert.IsInstanceOf(typeof(TagNameInvalidException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }

        [Test]
        public void TagParentTagTest()
        {
            try
            {
                this._documentParser.Parse(
                    this._resources["Com.ContentRendering.Api.ParserEngineComponentTest.Test.Input.TagParentTag.tem"],
                    this._outputNodeHelper);
            }
            catch (ParserException exception)
            {
                Assert.AreEqual(exception.Line, 1);
                Assert.AreEqual(exception.Column, 9);
                Assert.AreEqual(exception.Value, ',');
                Assert.AreEqual(exception.DebugBuffer, "[testOne");
                Assert.IsInstanceOf(typeof(TagNameInvalidException), exception.InnerException);

                return;
            }

            Assert.Fail();
        }
    }
}
